package com.qzuser.sendmessagebasic.server;

import com.qzuser.sendmessagebasic.common.exception.*;
import com.qzuser.sendmessagebasic.server.binding.Binding;
import com.qzuser.sendmessagebasic.server.dao.DiskCenter;
import com.qzuser.sendmessagebasic.server.dao.MemoryCenter;
import com.qzuser.sendmessagebasic.server.exchange.Exchange;
import com.qzuser.sendmessagebasic.server.exchange.ExchangeType;
import com.qzuser.sendmessagebasic.server.exchange.Router;
import com.qzuser.sendmessagebasic.server.message.BasicProperties;
import com.qzuser.sendmessagebasic.server.message.Message;
import com.qzuser.sendmessagebasic.server.queue.ConsumeCenter;
import com.qzuser.sendmessagebasic.server.queue.Consumer;
import com.qzuser.sendmessagebasic.server.queue.Queue;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

public class VirtualHost {
    private final String hostName;
    private final MemoryCenter memoryCenter = new MemoryCenter();
    private final DiskCenter diskCenter = new DiskCenter();
    private final Router router = new Router();
    private final Object exchangeLock = new Object();
    private final Object queueLock = new Object();
    private final ConsumeCenter consumeCenter = new ConsumeCenter(this);

    public VirtualHost(String name) {
        this.hostName = name;
        try {
            diskCenter.init();
            memoryCenter.recovery(diskCenter);
        } catch (DataBaseException e) {
            e.printStackTrace();
        }
    }

    public String getHostName() {
        return hostName;
    }

    public MemoryCenter getMemoryCenter() {
        return memoryCenter;
    }

    public DiskCenter getDiskCenter() {
        return diskCenter;
    }

    public boolean exchangeDeclare(String exchangeName, ExchangeType type, boolean durable, boolean autoDelete, Map<String, Object> arguments) {
        exchangeName = hostName + exchangeName;
        try {
            synchronized (exchangeLock) {
                Exchange exists = memoryCenter.getExchange(exchangeName);
                if (exists != null) {
                    System.out.println("[VirtualHost] 交换机添加成功：" + exchangeName);
                    return true;
                }
                Exchange exchange = new Exchange();
                exchange.setName(exchangeName);
                exchange.setType(type);
                exchange.setDurable(durable);
                exchange.setAutoDelete(autoDelete);
                exchange.setArguments(arguments);
                if (durable) {
                    diskCenter.insertExchange(exchange);
                }
                memoryCenter.addExchange(exchange);
                System.out.println("[VirtualHost] 交换机添加成功：" + exchangeName);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean exchangeDelete(String exchangeName) {
        exchangeName = hostName + exchangeName;
        try {
            synchronized (exchangeLock) {
                Exchange exchange = memoryCenter.getExchange(exchangeName);
                if (exchange == null) {
                    throw new VirtualHostException("[VirtualHost] 交换机不存在无法删除：" + exchangeName);
                }
                if (exchange.getDurable()) {
                    diskCenter.deleteExchange(exchangeName);
                }
                memoryCenter.deleteExchange(exchangeName);
                System.out.println("[VirtualHost] 交换机删除成功：" + exchangeName);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean queueDeclare(String queueName, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments) {
        queueName = hostName + queueName;
        try {
            synchronized (queueLock) {
                if (memoryCenter.getQueue(queueName) != null) {
                    System.out.println("[VirtualHost] 队列已经存在，无需重复创建：" + queueName);
                    return true;
                }
                Queue queue = new Queue();
                queue.setName(queueName);
                queue.setDurable(durable);
                queue.setExclusive(exclusive);
                queue.setAutoDelete(autoDelete);
                queue.setArguments(arguments);
                if (durable) {
                    diskCenter.insertQueue(queue);
                }
                memoryCenter.addQueue(queue);
                System.out.println("[VirtualHost] 队列创建成功：" + queueName);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean queueDelete(String queueName) {
        queueName = hostName + queueName;
        try {
            synchronized (queueLock) {
                Queue queue = memoryCenter.getQueue(queueName);
                if (queue == null) {
                    throw new VirtualHostException("[VirtualHost] 队列不存在无法删除：" + queueName);
                }
                if (queue.getDurable()) {
                    diskCenter.deleteQueue(queueName);
                }
                memoryCenter.deleteQueue(queueName);
                System.out.println("[VirtualHost] 队列删除成功：" + queueName);
                return true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean queueBind(String exchangeName, String queueName, String bindingKey) {
        exchangeName = hostName + exchangeName;
        queueName = hostName + queueName;
        try {
            synchronized (exchangeLock) {
                synchronized (queueLock) {
                    if (memoryCenter.getBinding(exchangeName, queueName) != null) {
                        throw new VirtualHostException("[VirtualHost] 绑定已经存在：" + exchangeName + "-" + bindingKey+ "-" + queueName);
                    }
                    if (!router.checkBindingKey(bindingKey)) {
                        throw new VirtualHostException("[VirtualHost] bindingKey非法：" + bindingKey);
                    }
                    Exchange exchange = memoryCenter.getExchange(exchangeName);
                    if (exchange == null) {
                        throw new VirtualHostException("[VirtualHost] 交换机不存在：" + exchangeName);
                    }
                    Queue queue = memoryCenter.getQueue(queueName);
                    if (queue == null) {
                        throw new VirtualHostException("[VirtualHost] 队列不存在：" + queueName);
                    }
                    Binding binding = new Binding();
                    binding.setExchangeName(exchangeName);
                    binding.setQueueName(queueName);
                    binding.setBindingKey(bindingKey);
                    if (exchange.getDurable() && queue.getDurable()) {
                        diskCenter.insertBinding(binding);
                    }
                    memoryCenter.addBinding(binding);
                    System.out.println("[VirtualHost] 交换机与队列绑定成功：" + exchangeName + "-" + bindingKey+ "-" + queueName);
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean queueUnbind(String exchangeName, String queueName) {
        exchangeName = hostName + exchangeName;
        queueName = hostName + queueName;
        try {
            synchronized (exchangeLock) {
                synchronized (queueLock) {
                    Binding binding = memoryCenter.getBinding(exchangeName, queueName);
                    if (binding == null) {
                        throw new VirtualHostException("[VirtualHost] 绑定关系不存在：" + exchangeName + "-" + queueName);
                    }
                    diskCenter.deleteBinding(binding);
                    memoryCenter.deleteBinding(exchangeName, queueName);
                    System.out.println("[VirtualHost] 交换机与队列解绑成功：" + exchangeName + "-" + queueName);
                    return true;
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean publish(String exchangeName, String routingKey, BasicProperties properties, byte[] body) {
        exchangeName = hostName + exchangeName;
        try {
            Exchange exchange = memoryCenter.getExchange(exchangeName);
            if (exchange == null) {
                throw new VirtualHostException("[VirtualHost] 消息发送失败：交换机不存在");
            }
            if (!router.checkRoutingKey(routingKey)) {
                throw new VirtualHostException("[VirtualHost] 消息发送失败：非法routingKey");
            }
            if (exchange.getType() == ExchangeType.DIRECT) {
                String queueName = hostName + routingKey;
                Queue queue = memoryCenter.getQueue(queueName);
                if (queue == null) {
                    throw new VirtualHostException("[VirtualHost] 消息发送失败：队列不存在");
                }
                Message message = Message.createMessageWithId(properties, routingKey, body);
                sendMessage(queue, message);
                System.out.println("[VirtualHost] 消息发送成功 -> "+queueName+"\n" + message);
            } else {
                ConcurrentHashMap<String, Binding> allBinding = memoryCenter.getAllBinding(exchangeName);
                for (Map.Entry<String, Binding> entry : allBinding.entrySet()) {
                    Binding binding = entry.getValue();
                    Queue queue = memoryCenter.getQueue(binding.getQueueName());
                    if (queue == null) {
                        System.out.println("[VirtualHost] 消息发送失败：" + entry.getKey() + "队列不存在");
                        continue;
                    }
                    Message message;
                    if (properties != null) {
                        BasicProperties propsCopy = new BasicProperties(properties);
                        message = Message.createMessageWithId(propsCopy, routingKey, body);
                    } else {
                        message = Message.createMessageWithId(properties, routingKey, body);
                    }
                    if (!router.route(exchange.getType(), binding, message)) {
                        continue;
                    }
                    sendMessage(queue, message);
                    System.out.println("[VirtualHost] 消息发送成功 -> " + queue.getName() +"\n" + message);
                }
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    private void sendMessage(Queue queue, Message message) throws ToolException, MessageFileException, InterruptedException {
        if (message.getDeliverMode() == 1) {
            diskCenter.sendMessage(queue, message);
        }
        memoryCenter.sendMessage(queue, message);
        consumeCenter.notifyConsume(queue.getName());
    }

    public boolean consume(String consumerTag, String queueName, boolean autoAck, Consumer consumer) {
        queueName = hostName + queueName;
        try {
            consumeCenter.addConsumer(consumerTag, queueName, autoAck, consumer);
            return true;
        } catch (ConsumeException e) {
            e.printStackTrace();
            return false;
        }
    }

    public boolean basicAck(String queueName, String messageId) {
        queueName = hostName + queueName;
        try {
            Queue queue = memoryCenter.getQueue(queueName);
            if (queue == null) {
                throw new VirtualHostException("[VirtualHost] 待确认消息队列不存在：" + queueName);
            }
            Message message = memoryCenter.getMessage(messageId);
            if (message == null) {
                throw new VirtualHostException("[VirtualHost] 待确认消息不存在：" + messageId);
            }
            if (message.getDeliverMode() == 1) {
                diskCenter.deleteMessage(queue, message, memoryCenter);
            }
            memoryCenter.deleteWaitAckMsg(queueName, messageId);
            memoryCenter.deleteMessage(messageId);
            System.out.println("[VirtualHost] 消息确认成功" + queueName + " -> " + messageId);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }
}
